import sqlite3
from typing import Dict, List, Tuple
from LogManager import log_output
from UserManager import DATABASE, UserManager
import time


# Interaction Database
DATABASE = 'database/interact_data.db'


class InteractionManager:
    """
        Tables in interact_data.db:
        view_info(view_info_id, user_id, book_id)
        view_reader(view_reader_id, user_id, book_id)
        view_stay(view_stay_id, user_id, book_id, recom_stay)
        view_speed(view_speed_id, user_id, book_id, reader_speed)
        view_rate(view_rate_id, user_id, book_id, rate)
        view_great(view_great_id, user_id, book_id, great_or_not)
    """

    def __init__(self, user_manager: UserManager):
        self.error_info = {
            'type': 1
        }
        self.user_manager: UserManager = user_manager
        self.database = DATABASE

    def get_conn(self):
        self.conn = sqlite3.connect(self.database)
        return self.conn

    def close_conn(self):
        if self.conn is None:
            return

        try:
            self.conn.close()
        except Exception as err:
            log_output(str(err))

        self.conn = None

    def __handle_view_info(self, user_id: int, book_id: int, ax, ay, az, t):
        try:
            sql = f'INSERT INTO view_info VALUES (NULL,{user_id},{book_id},{ax},{ay},{az},{t})'
            conn = self.get_conn()
            cursor = conn.cursor()
            cursor.execute(sql)

            conn.commit()
        except Exception as err:
            log_output(str(err))
            raise ValueError()
        finally:
            if cursor is not None:
                cursor.close()
            self.close_conn()

    def __handle_view_reader(self, user_id: int, book_id: int, ax, ay, az, t):
        try:
            sql = f'INSERT INTO view_reader VALUES (NULL,{user_id},{book_id},{ax},{ay},{az},{t})'
            conn = self.get_conn()
            cursor = conn.cursor()
            cursor.execute(sql)

            conn.commit()
        except Exception as err:
            log_output(str(err))
            raise ValueError()
        finally:
            if cursor is not None:
                cursor.close()
            self.close_conn()

    def __handle_view_stay(self, user_id: int, book_id: int, recom_stay: float, ax, ay, az, t):
        try:
            sql = f'INSERT INTO view_stay VALUES (NULL, {user_id},{book_id},{recom_stay},{ax},{ay},{az},{t})'
            conn = self.get_conn()
            cursor = conn.cursor()
            cursor.execute(sql)

            conn.commit()
        except Exception as err:
            log_output(str(err))
            raise ValueError()
        finally:
            if cursor is not None:
                cursor.close()
            self.close_conn()

    def __handle_view_rate(self, user_id: int, book_id: int, rate: int, ax, ay, az, t):
        try:
            sql = f'INSERT INTO view_rate VALUES (NULL,{user_id},{book_id},{rate},{ax},{ay},{az},{t})'
            conn = self.get_conn()
            cursor = conn.cursor()
            cursor.execute(sql)

            conn.commit()
        except Exception as err:
            log_output(str(err))
            raise ValueError()
        finally:
            if cursor is not None:
                cursor.close()
            self.close_conn()

    def __handle_view_great(self, user_id: int, book_id: int, great_or_not: int, ax, ay, az, t):
        try:
            sql = f'INSERT INTO view_great VALUES (NULL,{user_id},{book_id},{great_or_not},{ax},{ay},{az},{t})'
            conn = self.get_conn()
            cursor = conn.cursor()
            cursor.execute(sql)

            conn.commit()
        except Exception as err:
            log_output(str(err))
            raise ValueError()
        finally:
            if cursor is not None:
                cursor.close()
            self.close_conn()

    def __handle_view_speed(self, user_id: int, book_id: int, view_speed: List[float], ax, ay, az, t):
        try:
            conn = self.get_conn()
            cursor = conn.cursor()

            for speed in view_speed:
                sql = f'INSERT INTO view_speed VALUES (NULL,{user_id},{book_id},{speed},{ax},{ay},{az},{t})'
                cursor.execute(sql)

            conn.commit()
        except Exception as err:
            log_output(str(err))
            raise ValueError()
        finally:
            if cursor is not None:
                cursor.close()
            self.close_conn()

    def send_interaction(self, send_data: Dict[str, str]):
        if type(send_data) != dict:
            log_output('Send Interaction not Dict', print_to_screen=True)
            return self.error_info

        assert 'post_type' in send_data
        assert 'token' in send_data
        assert 'book_id' in send_data

        # Get user_id from token
        try:
            user_id = self.user_manager.get_user_id_with_token(
                send_data['token'])
        except Exception as err:
            log_output(err)
            raise ValueError()

        book_id = int(send_data['book_id'])

        ax, ay, az, t = 'NULL', 'NULL', 'NULL', time.time()
        if 'ax' in send_data and 'ay' in send_data and 'az' in send_data:
            ax = str(send_data['ax'])
            ay = str(send_data['ay'])
            az = str(send_data['az'])

        # Handle different post types
        if send_data['post_type'] == 'view_info':
            self.__handle_view_info(user_id, book_id, ax, ay, az, t)
        elif send_data['post_type'] == 'view_reader':
            self.__handle_view_reader(user_id, book_id, ax, ay, az, t)
        elif send_data['post_type'] == 'view_stay':
            assert 'recom_stay' in send_data
            recom_stay = float(send_data['recom_stay'])
            self.__handle_view_stay(
                user_id, book_id, recom_stay, ax, ay, az, t)
        elif send_data['post_type'] == 'view_speed':
            assert 'reader_speed' in send_data
            reader_speed = send_data['reader_speed']
            assert type(reader_speed) == list
            self.__handle_view_speed(
                user_id, book_id, reader_speed, ax, ay, az, t)
        elif send_data['post_type'] == 'view_rate':
            assert 'rate' in send_data
            rate = int(send_data['rate'])
            self.__handle_view_rate(user_id, book_id, rate, ax, ay, az, t)
        elif send_data['post_type'] == 'view_great':
            assert 'great_or_not' in send_data
            great_or_not = int(send_data['great_or_not'])
            self.__handle_view_great(
                user_id, book_id, great_or_not, ax, ay, az, t)
        else:
            log_output(f'Illegal post type: {send_data["post_type"]}')
            raise ValueError()

    def request_book_rate(self, send_data):
        assert type(send_data) == dict
        assert 'book_id' in send_data

        try:
            book_id = int(send_data['book_id'])
            sql = f'SELECT AVG(rate) FROM view_rate WHERE book_id = {book_id}'
            conn = self.get_conn()
            cursor = conn.cursor()
            rows = cursor.execute(sql)

            result = None

            for row in rows:
                result = row[0]

            if result is None or type(result) != float:
                return_dict = {
                    'ok': True,
                    'rate': '暂无数据'
                }
            else:
                return_dict = {
                    'ok': True,
                    'rate': str(result)[:3]
                }

            return return_dict
        except Exception as err:
            log_output(str(err))
            raise ValueError()
        finally:
            if cursor is not None:
                cursor.close()
            self.close_conn()

